package com.bnyy.medicalHousekeeper.moudle.message;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

import androidx.annotation.Nullable;

import com.blankj.utilcode.util.NetworkUtils;
import com.bnyy.common.Constant;
import com.bnyy.medicalHousekeeper.UserInfoManager;
import com.bnyy.message.bean.Message;
import com.bnyy.message.bean.chat.ChatMessage;
import com.bnyy.message.bean.chat.message_data.AlarmMessage;
import com.bnyy.message.bean.chat.message_data.ArticleMessage;
import com.bnyy.message.bean.chat.message_data.GroupChatActivityMessage;
import com.bnyy.message.bean.chat.message_data.GroupChatVoteMessage;
import com.bnyy.message.bean.chat.message_data.HealthWeeklyMessage;
import com.bnyy.message.bean.chat.message_data.InvitationMessage;
import com.bnyy.message.bean.chat.message_data.MallGoodsMessage;
import com.bnyy.message.bean.chat.message_data.MessageData;
import com.bnyy.message.bean.chat.message_data.NoticeAlarmMessage;
import com.bnyy.message.bean.chat.message_data.NoticeGoodsMessage;
import com.bnyy.message.bean.chat.message_data.NoticeLocationAuthorityMessage;
import com.bnyy.message.bean.chat.message_data.ServiceGoodsMessage;
import com.bnyy.message.bean.chat.message_data.TipsMessageList;
import com.bnyy.message.bean.chat.message_data.UserHomePageMessage;
import com.bnyy.message.bean.chat.message_data.VerificationMessage;
import com.bnyy.message.enums.ChatMessageStatus;
import com.bnyy.message.enums.MessageType;
import com.bnyy.message.event.ErrorMessageEvent;
import com.bnyy.message.event.ReceiveMessageEvent;
import com.bnyy.message.event.SendMessageEvent;
import com.bnyy.medicalHousekeeper.request.RequestManager;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Objects;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import okio.ByteString;

/**
 * Author : 关炳鹏
 * Description :
 * Date : 2022/6/30
 **/
public class MessageService extends Service {
    private static final String TAG = "MessageService";

    private Timer heartBeatTimer;
    private boolean connected = false;
    private Gson gson;
    private WebSocket webSocket;
    private Context context;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        EventBus.getDefault().register(this);

        NetworkUtils.registerNetworkStatusChangedListener(new NetworkUtils.OnNetworkStatusChangedListener() {
            @Override
            public void onDisconnected() {
                disconnect();
            }

            @Override
            public void onConnected(NetworkUtils.NetworkType networkType) {
                connect();
            }
        });
        gson = new Gson();
        connect();
    }

    private void connect() {
        if (NetworkUtils.isConnected()) {
            String url;
            if (RequestManager.getInstance().isFormal()) {
                url = "wss://" + Constant.NetWork.SOCKET_URL_FORMAL;
            } else {
                url = "ws://" + Constant.NetWork.SOCKET_URL_LOCAL;
            }

            url += Constant.NetWork.WEB_SOCKET_URL;

            Log.e(TAG, url);

            Request request = new Request.Builder().get().url(url).build();

            OkHttpClient okHttpClient = new OkHttpClient.Builder()
                    .readTimeout(3, TimeUnit.SECONDS)//设置读取超时时间
                    .writeTimeout(3, TimeUnit.SECONDS)//设置写的超时时间
                    .connectTimeout(3, TimeUnit.SECONDS)//设置连接超时时间
                    .build();

            webSocket = okHttpClient.newWebSocket(request, new WebSocketListener() {
                @Override
                public void onOpen(WebSocket webSocket, okhttp3.Response response) {
                    super.onOpen(webSocket, response);
                    Log.e(TAG, "onOpen");
                    connected = true;
                    login();
//                    if (UserInfoManager.getInstance().getLoginUser() != null) {
//                        MessageManager.getOffLineChatMessage(1);
//                    }

                    while (unsendMessages.size() > 0) {
                        sendMessage(unsendMessages.poll());
                    }
                }

                @Override
                public void onMessage(WebSocket webSocket, String text) {
                    super.onMessage(webSocket, text);
                    Log.e(TAG, "onMessage = " + text);

                    if (UserInfoManager.getInstance().getLoginUserId() != 0) {
                        if (text.equals("ping")) {

                        } else {
                            try {
                                JsonParser jsonParser = new JsonParser();
                                JsonObject jsonObject = jsonParser.parse(text).getAsJsonObject();

                                int msgType = jsonObject.get("msg_type").getAsInt();
                                int code = jsonObject.get("code").getAsInt();
                                if (msgType != 101) {
                                    JsonElement jsonElement = jsonObject.get("data");
                                    if (jsonElement != null) {
                                        MessageType messageType = MessageType.getMessageType(msgType);
                                        JsonObject dataRoot = jsonElement.getAsJsonObject();
                                        if (code == 0) {
                                            Log.e(TAG, messageType.getType() + " " + gson.toJson(dataRoot));

                                            if (messageType.isChatMessage() || messageType.isNoticeMessage()) {
                                                ChatMessage chatMessage = gson.fromJson(dataRoot, ChatMessage.class);
                                                String msgId = chatMessage.getMsgId();
                                                int senderUserId = chatMessage.getSenderId();

                                                int loginUserId = UserInfoManager.getInstance().getLoginUserId();

                                                boolean post = true;
                                                long tag = chatMessage.getTag();

                                                if (senderUserId == loginUserId) {
                                                    if (tag == 0) {
                                                        post = false;
                                                        MessageManager.updateSendStatus(msgId, ChatMessageStatus.SUCCESS);
                                                    }
                                                }

                                                if (post) {

                                                    HashMap<String, Object> params = new HashMap<>();
                                                    params.put("msg_type", messageType.getType());

                                                    HashMap<String, String> dataMap = new HashMap<>();
                                                    dataMap.put("msg_id", msgId);

                                                    params.put("data", dataMap);

                                                    sendMessage(gson.toJson(params));

                                                    chatMessage.setChatMessageStatus(ChatMessageStatus.SUCCESS);

                                                    JsonElement dataElement = dataRoot.get("data");
                                                    if (dataElement != null) {
                                                        JsonObject dataJsonObject = dataElement.getAsJsonObject();
                                                        MessageData messageData = null;

                                                        switch (messageType) {
                                                            case MALL_GOODS:
                                                                messageData = gson.fromJson(dataJsonObject, MallGoodsMessage.class);
                                                                break;
                                                            case SERVICE_GOODS:
                                                                messageData = gson.fromJson(dataJsonObject, ServiceGoodsMessage.class);
                                                                break;
                                                            case ALARM:
                                                                messageData = gson.fromJson(dataJsonObject, AlarmMessage.class);
                                                                break;
                                                            case GROUP_CHAT_VERIFICATION:
                                                                messageData = gson.fromJson(dataJsonObject, VerificationMessage.class);
                                                                break;
                                                            case GROUP_CHAT_INVITATION:
                                                                messageData = gson.fromJson(dataJsonObject, InvitationMessage.class);
                                                                break;
                                                            case USER_HOMEPAGE:
                                                                messageData = gson.fromJson(dataJsonObject, UserHomePageMessage.class);
                                                                break;
                                                            case HEALTH_WEEKLY:
                                                                messageData = gson.fromJson(dataJsonObject, HealthWeeklyMessage.class);
                                                                break;
                                                            case GROUP_CHAT_VOTE:
                                                                messageData = gson.fromJson(dataJsonObject, GroupChatVoteMessage.class);
                                                                break;
                                                            case GROUP_CHAT_ACTIVITY:
                                                                messageData = gson.fromJson(dataJsonObject, GroupChatActivityMessage.class);
                                                                break;
                                                            case NOTICE_ALARM:
                                                                messageData = gson.fromJson(dataJsonObject, NoticeAlarmMessage.class);
                                                                break;
                                                            case NOTICE_LOCATION_AUTHORITY:
                                                                messageData = gson.fromJson(dataJsonObject, NoticeLocationAuthorityMessage.class);
                                                                break;
                                                            case NOTICE_GOODS:
                                                                NoticeGoodsMessage noticeGoodsMessage = gson.fromJson(dataJsonObject, NoticeGoodsMessage.class);
                                                                noticeGoodsMessage.setGoodsJson(gson.toJson(noticeGoodsMessage.getGoodsMessages()));
                                                                messageData = noticeGoodsMessage;
                                                                break;
                                                            case CHAT_TIPS:
                                                                if (dataJsonObject.has("keywords")) {
                                                                    messageData = new TipsMessageList(msgId, new Gson().toJson(dataJsonObject.get("keywords")));
                                                                }
                                                                break;
                                                            case ARTICLE:
                                                                messageData = gson.fromJson(dataJsonObject, ArticleMessage.class);
                                                                break;
                                                        }
                                                        if (messageData != null) {
                                                            messageData.setMsgId(msgId);
                                                            chatMessage.setMessageData(messageData);
                                                        }
                                                    }
                                                    MessageManager.save(chatMessage);

                                                    EventBus.getDefault().post(new ReceiveMessageEvent(messageType, chatMessage));
                                                }
                                            } else {
                                                switch (messageType) {
                                                    case CHECK_AUTH:
                                                    case RECEIVE_REQUEST_AUTHORITY:
                                                        EventBus.getDefault().post(new ReceiveMessageEvent(messageType, gson.fromJson(dataRoot, Message.class)));
                                                        break;
                                                }
                                            }
                                        } else {
                                            EventBus.getDefault().post(new ErrorMessageEvent(messageType, gson.fromJson(dataRoot, Message.class), code));
                                        }
                                    }
                                }

                            } catch (Exception e) {
                                Log.e(TAG, "Exception = " + Objects.requireNonNull(e.getMessage()));
                                reconnect();
                            }
                        }
                    }
                }

                @Override
                public void onMessage(WebSocket webSocket, ByteString bytes) {
                    super.onMessage(webSocket, bytes);
                }

                @Override
                public void onClosing(WebSocket webSocket, int code, String reason) {
                    super.onClosing(webSocket, code, reason);
                    Log.e(TAG, "onClosing code = " + code + " reason = " + reason);
                    reconnect();
                }

                @Override
                public void onClosed(WebSocket webSocket, int code, String reason) {
                    super.onClosed(webSocket, code, reason);
                    Log.e(TAG, "onClosed code = " + code + " reason = " + reason);
                    reconnect();
                }

                @Override
                public void onFailure(WebSocket webSocket, Throwable t, okhttp3.Response response) {
                    t.printStackTrace();

                    super.onFailure(webSocket, t, response);
                    Log.e(TAG, "onFailure " + t.getMessage());
                    reconnect();
                }
            });
        }
    }

    private Timer reconnectTimer;

    private void reconnect() {
        if (UserInfoManager.getInstance().getLoginUser() != null) {
            if (reconnectTimer == null) {
                reconnectTimer = new Timer();
                reconnectTimer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        reconnectTimer = null;
                        connect();
                    }
                }, 3000);
            }
        }
    }

    private void login() {
        if (UserInfoManager.getInstance().getLoginUser() != null) {
            HashMap<String, Object> params = new HashMap<>();
            params.put("token", RequestManager.getToken());
            params.put("msg_type", 101);
            sendMessage(gson.toJson(params));

            if (heartBeatTimer == null) {
                heartBeatTimer = new Timer();
                heartBeatTimer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        Log.e(TAG, "heartBeatTimer");
                        if (UserInfoManager.getInstance().getLoginUser() == null) {
                            disconnect();
                        } else {
                            login();
                        }
                    }
                }, 10 * 1000, 30 * 1000);
            }
        }
    }

    public void disconnect() {
        Log.e(TAG, "disconnect");
        connected = false;
        if (webSocket != null) {
            webSocket.cancel();
            webSocket = null;
        }

        if (heartBeatTimer != null) {
            heartBeatTimer.cancel();
            heartBeatTimer = null;
        }
    }

    private LinkedList<String> unsendMessages = new LinkedList<>();

    public void sendMessage(String msg) {
        Log.e(TAG, "sendMessage = " + msg);
        if (webSocket == null) {
            unsendMessages.add(msg);
            reconnect();
        } else {
            webSocket.send(msg);
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEvent(SendMessageEvent event) {
        HashMap<String, Object> params = new HashMap<>();
        Message message = event.getMessage();
        MessageType messageType = message.getMessageType();

        params.put("msg_type", messageType.getType());

        switch (messageType) {
            case LOGOUT: // 退出登录
                params.put("token", RequestManager.getToken());
                disconnect();
                break;
            case REQUEST_AUTHORITY:
                params.put("wear_id", message.getWear_id());
                break;
            case RECEIVE_REQUEST_AUTHORITY:
                params.put("wear_id", message.getWear_id());
                params.put("location_auth", message.getLocation_auth());
                params.put("user_id", message.getSenderId());
                break;
            default:
                params.put("data", message);
                break;
        }
        sendMessage(gson.toJson(params));
    }
}



















